Remove unused variable.
authorOwen Taylor <otaylor@redhat.com>
Wed, 17 Jan 2001 20:05:08 +0000 (20:05 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Wed, 17 Jan 2001 20:05:08 +0000 (20:05 +0000)
Tue Jan  9 11:20:48 2001  Owen Taylor  <otaylor@redhat.com>

* gdk/x11/gdkdnd-x11.c: Remove unused variable.

* gtk/gtkdnd.c: Encapsulate storing and retrieving info
structures in functions. Fixes bug where gtk_dataset_*
was accidentally still being used in one place, causing
        every dest side event to be treated independently.

* gtk/gtkdnd.c: Remove last vestages of handling
::draw (fixes warning)

* gtk/gtkentry.[ch]: Add drag and drop support.

* gtk/gtkdnd.[ch] gtk/gtktextview.c gtk/gtkentry.c: Add
new function gtk_check_drag_threshhold() for checking
to check if (dx,dy) has exceeded the threshhold for starting
a drag and use it everywhere.

gdk/x11/gdkdnd-x11.c
gtk/gtkdnd.c
gtk/gtkdnd.h
gtk/gtkentry.c
gtk/gtkentry.h
gtk/gtktextview.c

index 976abaf3a7b81dee7a4ac5a2d83a50e8b045e590..4dc4d3ce98bcc89263355fa53731c53a199aa363 100644 (file)
@@ -2473,8 +2473,6 @@ xdnd_manage_source_filter (GdkDragContext *context,
                           GdkWindow      *window,
                           gboolean        add_filter)
 {
-  gint old_warnings = 0;       /* quiet gcc */
-
   gdk_error_trap_push ();
 
   if (!GDK_WINDOW_DESTROYED (window))
index 0abb2d9d632e90e5c311d17828f9c20a485a9532..78ca1245ef570058770c839a930ad372df24bf8c 100644 (file)
@@ -183,39 +183,43 @@ static GdkCursor *   gtk_drag_get_cursor         (GdkDragAction action);
 static GtkWidget    *gtk_drag_get_ipc_widget     (void);
 static void          gtk_drag_release_ipc_widget (GtkWidget      *widget);
 
-static void          gtk_drag_highlight_paint    (GtkWidget      *widget);
 static gboolean      gtk_drag_highlight_expose   (GtkWidget      *widget,
                                                  GdkEventExpose *event,
                                                  gpointer        data);
 
-
-static GdkAtom   gtk_drag_dest_find_target    (GtkWidget          *widget,
-                                              GtkDragDestSite    *site,
-                                              GdkDragContext     *context);
-static void      gtk_drag_selection_received  (GtkWidget          *widget,
-                                              GtkSelectionData   *selection_data,
-                                              guint32             time,
-                                              gpointer            data);
-static void      gtk_drag_find_widget         (GtkWidget          *widget,
-                                              GtkDragFindData    *data);
-static void      gtk_drag_proxy_begin         (GtkWidget          *widget,
-                                              GtkDragDestInfo    *dest_info);
-static void      gtk_drag_dest_info_destroy   (gpointer            data);
-static void      gtk_drag_dest_realized       (GtkWidget          *widget);
-static void      gtk_drag_dest_site_destroy   (gpointer            data);
-static void      gtk_drag_dest_leave          (GtkWidget          *widget,
-                                              GdkDragContext     *context,
-                                              guint               time);
-static gboolean  gtk_drag_dest_motion         (GtkWidget         *widget,
-                                              GdkDragContext     *context,
-                                              gint                x,
-                                              gint                y,
-                                              guint               time);
-static gboolean  gtk_drag_dest_drop           (GtkWidget         *widget,
-                                              GdkDragContext     *context,
-                                              gint                x,
-                                              gint                y,
-                                              guint               time);
+static GdkAtom  gtk_drag_dest_find_target   (GtkWidget        *widget,
+                                            GtkDragDestSite  *site,
+                                            GdkDragContext   *context);
+static void     gtk_drag_selection_received (GtkWidget        *widget,
+                                            GtkSelectionData *selection_data,
+                                            guint32           time,
+                                            gpointer          data);
+static void     gtk_drag_find_widget        (GtkWidget        *widget,
+                                            GtkDragFindData  *data);
+static void     gtk_drag_proxy_begin        (GtkWidget        *widget,
+                                            GtkDragDestInfo  *dest_info,
+                                            guint32           time);
+static void     gtk_drag_dest_realized      (GtkWidget        *widget);
+static void     gtk_drag_dest_site_destroy  (gpointer          data);
+static void     gtk_drag_dest_leave         (GtkWidget        *widget,
+                                            GdkDragContext   *context,
+                                            guint             time);
+static gboolean gtk_drag_dest_motion        (GtkWidget        *widget,
+                                            GdkDragContext   *context,
+                                            gint              x,
+                                            gint              y,
+                                            guint             time);
+static gboolean gtk_drag_dest_drop          (GtkWidget        *widget,
+                                            GdkDragContext   *context,
+                                            gint              x,
+                                            gint              y,
+                                            guint             time);
+
+static GtkDragDestInfo *  gtk_drag_get_dest_info     (GdkDragContext *context,
+                                                     gboolean        create);
+static GtkDragSourceInfo *gtk_drag_get_source_info   (GdkDragContext *context,
+                                                     gboolean        create);
+static void               gtk_drag_clear_source_info (GdkDragContext *context);
 
 static void gtk_drag_source_check_selection    (GtkDragSourceInfo *info, 
                                                GdkAtom            selection,
@@ -239,7 +243,7 @@ static void gtk_drag_selection_get             (GtkWidget         *widget,
                                                gpointer           data);
 static gint gtk_drag_anim_timeout              (gpointer           data);
 static void gtk_drag_remove_icon               (GtkDragSourceInfo *info);
-static void gtk_drag_source_info_destroy       (gpointer           data);
+static void gtk_drag_source_info_destroy       (GtkDragSourceInfo *info);
 static void gtk_drag_update                    (GtkDragSourceInfo *info,
                                                gint               x_root,
                                                gint               y_root,
@@ -739,20 +743,22 @@ gtk_drag_finish (GdkDragContext *context,
 }
 
 /*************************************************************
- * gtk_drag_highlight_paint:
- *     Paint a highlight indicating drag status onto the widget.
+ * gtk_drag_highlight_expose:
+ *     Callback for expose_event for highlighted widgets.
  *   arguments:
  *     widget:
+ *     event:
+ *     data:
  *   results:
  *************************************************************/
 
-static void 
-gtk_drag_highlight_paint (GtkWidget  *widget)
+static gboolean
+gtk_drag_highlight_expose (GtkWidget      *widget,
+                          GdkEventExpose *event,
+                          gpointer        data)
 {
   gint x, y, width, height;
-
-  g_return_if_fail (widget != NULL);
-
+  
   if (GTK_WIDGET_DRAWABLE (widget))
     {
       if (GTK_WIDGET_NO_WINDOW (widget))
@@ -778,24 +784,7 @@ gtk_drag_highlight_paint (GtkWidget  *widget)
                          FALSE,
                          x, y, width - 1, height - 1);
     }
-}
 
-/*************************************************************
- * gtk_drag_highlight_expose:
- *     Callback for expose_event for highlighted widgets.
- *   arguments:
- *     widget:
- *     event:
- *     data:
- *   results:
- *************************************************************/
-
-static gboolean
-gtk_drag_highlight_expose (GtkWidget      *widget,
-                          GdkEventExpose *event,
-                          gpointer        data)
-{
-  gtk_drag_highlight_paint (widget);
   return TRUE;
 }
 
@@ -830,9 +819,6 @@ gtk_drag_unhighlight (GtkWidget *widget)
 {
   g_return_if_fail (widget != NULL);
 
-  gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
-                                GTK_SIGNAL_FUNC (gtk_drag_highlight_paint),
-                                NULL);
   gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
                                 GTK_SIGNAL_FUNC (gtk_drag_highlight_expose),
                                 NULL);
@@ -980,21 +966,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel,
 
   context = event->dnd.context;
 
-  info = g_dataset_get_data (context, "gtk-info");
-  if (!info)
-    {
-      info = g_new (GtkDragDestInfo, 1);
-      info->widget = NULL;
-      info->context = event->dnd.context;
-      info->proxy_source = NULL;
-      info->proxy_data = NULL;
-      info->dropped = FALSE;
-      info->proxy_drop_wait = FALSE;
-      g_object_set_qdata_full (G_OBJECT (context),
-                              g_quark_from_static_string ("gtk-info"),
-                              info,
-                              gtk_drag_dest_info_destroy);
-    }
+  info = gtk_drag_get_dest_info (context, TRUE);
 
   /* Find the widget for the event */
   switch (event->type)
@@ -1124,7 +1096,7 @@ gtk_drag_selection_received (GtkWidget        *widget,
   drop_widget = data;
 
   context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context");
-  info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_dest_info (context, FALSE);
 
   if (info->proxy_data && 
       info->proxy_data->target == selection_data->target)
@@ -1318,18 +1290,29 @@ gtk_drag_find_widget (GtkWidget       *widget,
 
 static void
 gtk_drag_proxy_begin (GtkWidget       *widget, 
-                     GtkDragDestInfo *dest_info)
+                     GtkDragDestInfo *dest_info,
+                     guint32          time)
 {
   GtkDragSourceInfo *source_info;
   GList *tmp_list;
+  GdkDragContext *context;
+  GtkWidget *ipc_widget;
+
+  if (dest_info->proxy_source)
+    {
+      gdk_drag_abort (dest_info->proxy_source->context, time);
+      gtk_drag_source_info_destroy (dest_info->proxy_source);
+      dest_info->proxy_source = NULL;
+    }
   
-  source_info = g_new0 (GtkDragSourceInfo, 1);
-  source_info->ipc_widget = gtk_drag_get_ipc_widget ();
-  
-  source_info->widget = widget;
-  gtk_widget_ref (source_info->widget);
-  source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
-                                        dest_info->context->targets);
+  ipc_widget = gtk_drag_get_ipc_widget ();
+  context = gdk_drag_begin (ipc_widget->window,
+                           dest_info->context->targets);
+
+  source_info = gtk_drag_get_source_info (context, TRUE);
+
+  source_info->ipc_widget = ipc_widget;
+  source_info->widget = gtk_widget_ref (widget);
 
   source_info->target_list = gtk_target_list_new (NULL, 0);
   tmp_list = dest_info->context->targets;
@@ -1342,11 +1325,7 @@ gtk_drag_proxy_begin (GtkWidget       *widget,
 
   source_info->proxy_dest = dest_info;
   
-  g_object_set_qdata (G_OBJECT (source_info->context),
-                      g_quark_from_static_string ("gtk-info"),
-                      source_info);
-  
-  gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget), 
+  gtk_signal_connect (GTK_OBJECT (ipc_widget), 
                      "selection_get",
                      GTK_SIGNAL_FUNC (gtk_drag_selection_get), 
                      source_info);
@@ -1362,6 +1341,59 @@ gtk_drag_dest_info_destroy (gpointer data)
   g_free (info);
 }
 
+static GtkDragDestInfo *
+gtk_drag_get_dest_info (GdkDragContext *context,
+                       gboolean        create)
+{
+  GtkDragDestInfo *info;
+  static GQuark info_quark = 0;
+  if (!info_quark)
+    info_quark = g_quark_from_static_string ("gtk-dest-info");
+  
+  info = g_object_get_qdata (G_OBJECT (context), info_quark);
+  if (!info && create)
+    {
+      info = g_new (GtkDragDestInfo, 1);
+      info->widget = NULL;
+      info->context = context;
+      info->proxy_source = NULL;
+      info->proxy_data = NULL;
+      info->dropped = FALSE;
+      info->proxy_drop_wait = FALSE;
+      g_object_set_qdata_full (G_OBJECT (context), info_quark,
+                              info, gtk_drag_dest_info_destroy);
+    }
+
+  return info;
+}
+
+static GQuark dest_info_quark = 0;
+
+static GtkDragSourceInfo *
+gtk_drag_get_source_info (GdkDragContext *context,
+                         gboolean        create)
+{
+  GtkDragSourceInfo *info;
+  if (!dest_info_quark)
+    dest_info_quark = g_quark_from_static_string ("gtk-source-info");
+  
+  info = g_object_get_qdata (G_OBJECT (context), dest_info_quark);
+  if (!info && create)
+    {
+      info = g_new0 (GtkDragSourceInfo, 1);
+      info->context = context;
+      g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
+    }
+
+  return info;
+}
+
+static void
+gtk_drag_clear_source_info (GdkDragContext *context)
+{
+  g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
+}
+
 static void
 gtk_drag_dest_realized (GtkWidget *widget)
 {
@@ -1395,11 +1427,14 @@ gtk_drag_dest_leave (GtkWidget      *widget,
 
   if (site->do_proxy)
     {
-      GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
-                                                  g_quark_from_static_string ("gtk-info"));
+      GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
 
-      if (info->proxy_source && !info->dropped)
-       gdk_drag_abort (info->proxy_source->context, time);
+      if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped)
+       {
+         gdk_drag_abort (info->proxy_source->context, time);
+         gtk_drag_source_info_destroy (info->proxy_source);
+         info->proxy_source = NULL;
+       }
       
       return;
     }
@@ -1437,11 +1472,10 @@ gtk_drag_dest_motion (GtkWidget      *widget,
       GdkWindow *dest_window;
       GdkDragProtocol proto;
        
-      GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context),
-                                                 g_quark_from_static_string ("gtk-info"));
+      GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE);
 
-      if (!info->proxy_source)
-       gtk_drag_proxy_begin (widget, info);
+      if (!info->proxy_source || info->proxy_source->widget != widget)
+       gtk_drag_proxy_begin (widget, info, time);
 
       current_event = gtk_get_current_event ();
 
@@ -1535,8 +1569,7 @@ gtk_drag_dest_drop (GtkWidget          *widget,
   site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest");
   g_return_val_if_fail (site != NULL, FALSE);
 
-  info = g_object_get_qdata (G_OBJECT (context),
-                             g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_dest_info (context, FALSE);
   g_return_val_if_fail (info != NULL, FALSE);
 
   info->drop_x = x;
@@ -1560,7 +1593,7 @@ gtk_drag_dest_drop (GtkWidget          *widget,
          GdkWindow *dest_window;
          GdkDragProtocol proto;
          
-         gtk_drag_proxy_begin (widget, info);
+         gtk_drag_proxy_begin (widget, info, time);
          info->proxy_drop_wait = TRUE;
          info->proxy_drop_time = time;
          
@@ -1596,7 +1629,6 @@ gtk_drag_dest_drop (GtkWidget          *widget,
            gtk_drag_source_check_selection (info->proxy_source, selection, time);
 
          gdk_event_free (current_event);
-      
        }
 
       return TRUE;
@@ -1650,6 +1682,8 @@ gtk_drag_begin (GtkWidget         *widget,
   GList *tmp_list;
   guint32 time = GDK_CURRENT_TIME;
   GdkDragAction possible_actions, suggested_action;
+  GdkDragContext *context;
+  GtkWidget *ipc_widget;
 
   g_return_val_if_fail (widget != NULL, NULL);
   g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
@@ -1658,12 +1692,6 @@ gtk_drag_begin (GtkWidget         *widget,
   if (event)
     time = gdk_event_get_time (event);
 
-  info = g_new0 (GtkDragSourceInfo, 1);
-  info->ipc_widget = gtk_drag_get_ipc_widget ();
-  source_widgets = g_slist_prepend (source_widgets, info->ipc_widget);
-
-  gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
-
   tmp_list = g_list_last (target_list->list);
   while (tmp_list)
     {
@@ -1673,15 +1701,20 @@ gtk_drag_begin (GtkWidget         *widget,
       tmp_list = tmp_list->prev;
     }
 
-  info->widget = widget;
-  gtk_widget_ref (info->widget);
-  
-  info->context = gdk_drag_begin (info->ipc_widget->window, targets);
+  ipc_widget = gtk_drag_get_ipc_widget ();
+  source_widgets = g_slist_prepend (source_widgets, ipc_widget);
+
+  context = gdk_drag_begin (ipc_widget->window, targets);
   g_list_free (targets);
   
-  g_object_set_qdata (G_OBJECT (info->context),
-                     g_quark_from_static_string ("gtk-info"), info);
+  info = gtk_drag_get_source_info (context, TRUE);
+  
+  info->ipc_widget = ipc_widget;
+  gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info);
+
+  info->widget = gtk_widget_ref (widget);
 
+  
   info->button = button;
   info->target_list = target_list;
   gtk_target_list_ref (target_list);
@@ -1916,8 +1949,7 @@ gtk_drag_set_icon_window (GdkDragContext *context,
   g_return_if_fail (context != NULL);
   g_return_if_fail (widget != NULL);
 
-  info = g_object_get_qdata (G_OBJECT (context),
-                            g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_source_info (context, FALSE);
   gtk_drag_remove_icon (info);
 
   info->icon_window = widget;
@@ -2108,8 +2140,7 @@ gtk_drag_source_handle_event (GtkWidget *widget,
   g_return_if_fail (event != NULL);
 
   context = event->dnd.context;
-  info = g_object_get_qdata (G_OBJECT (context),
-                            g_quark_from_static_string ("gtk-info"));
+  info = gtk_drag_get_source_info (context, FALSE);
   if (!info)
     return;
 
@@ -2288,8 +2319,7 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info,
          /* Mark the context as dead, so if the destination decides
           * to respond really late, we still are OK.
           */
-         g_object_set_qdata (G_OBJECT (info->context),
-                             g_quark_from_static_string ("gtk-info"), NULL);
+         gtk_drag_clear_source_info (info->context);
          gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim);
        }
     }
@@ -2410,9 +2440,9 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
                  GDK_BUTTON1_MASK << (i - 1))
                break;
            }
-         
-         if (MAX (ABS (site->x - event->motion.x),
-                  ABS (site->y - event->motion.y)) > 3)
+
+         if (gtk_drag_check_threshold (widget, site->x, site->y,
+                                       event->motion.x, event->motion.y))
            {
              GtkDragSourceInfo *info;
              GdkDragContext *context;
@@ -2422,10 +2452,7 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
                                        site->actions, 
                                        i, event);
 
-             
-             info = g_object_get_qdata (G_OBJECT (context),
-                                         g_quark_from_static_string ("gtk-info"));
-
+             info = gtk_drag_get_source_info (context, FALSE);
              if (!info->icon_window)
                {
                  if (site->pixmap)
@@ -2578,11 +2605,9 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info)
 }
 
 static void
-gtk_drag_source_info_destroy (gpointer data)
+gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
 {
-  GtkDragSourceInfo *info = data;
-
-  gtk_drag_remove_icon (data);
+  gtk_drag_remove_icon (info);
 
   if (!info->proxy_dest)
     gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end", 
@@ -2599,7 +2624,7 @@ gtk_drag_source_info_destroy (gpointer data)
 
   gtk_target_list_unref (info->target_list);
 
-  g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL);
+  gtk_drag_clear_source_info (info->context);
   gdk_drag_context_unref (info->context);
 
   if (info->drop_timeout)
@@ -2854,3 +2879,30 @@ gtk_drag_abort_timeout (gpointer data)
   
   return FALSE;
 }
+
+/**
+ * gtk_drag_check_threshold:
+ * @widget: a #GtkWidget
+ * @start_x: X coordinate of start of drag
+ * @start_y: Y coordinate of start of drag
+ * @current_x: current X coordinate
+ * @current_y: current Y coordinate
+ * 
+ * Checks to see if a mouse drag starting at (start_x, start_y) and ending
+ * at (current_x, current_y) has passed the GTK drag threshhold, and thus
+ * should trigger the beginning of a drag-and-drop operation.
+ *
+ * Return Value: If the drag threshold has been passed.
+ **/
+gboolean
+gtk_drag_check_threshold (GtkWidget *widget,
+                         gint       start_x,
+                         gint       start_y,
+                         gint       current_x,
+                         gint       current_y)
+{
+#define DRAG_THRESHOLD 8
+
+  return (ABS (current_x - start_x) > DRAG_THRESHOLD ||
+         ABS (current_y - start_y) > DRAG_THRESHOLD);
+}
index 84e7da2c52039f1d3ef7928778ba890a4b1ef065..e1c23b942b4e87c7ec2daa76e03c7b4bff9ff563 100644 (file)
@@ -131,6 +131,12 @@ void gtk_drag_set_default_icon (GdkColormap   *colormap,
                                gint           hot_y);
 
 
+gboolean gtk_drag_check_threshold (GtkWidget *widget,
+                                  gint       start_x,
+                                  gint       start_y,
+                                  gint       current_x,
+                                  gint       current_y);
+
 /* Internal functions */
 void gtk_drag_source_handle_event (GtkWidget *widget,
                                   GdkEvent  *event);
index f2edb59daadb718ff295193201d8f20df02ca747..ecfcb86a8313f2d25282b42b35e0d77d142f6b79 100644 (file)
@@ -31,6 +31,7 @@
 #include "gdk/gdkkeysyms.h"
 #include "gtkbindings.h"
 #include "gtkclipboard.h"
+#include "gtkdnd.h"
 #include "gtkentry.h"
 #include "gtkimmulticontext.h"
 #include "gtkintl.h"
@@ -76,6 +77,19 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+typedef enum {
+  CURSOR_STANDARD,
+  CURSOR_DND
+} CursorType;
+
+static GtkTargetEntry target_table[] = {
+  { "UTF8_STRING",   0, 0 },
+  { "COMPOUND_TEXT", 0, 0 },
+  { "TEXT",          0, 0 },
+  { "text/plain",    0, 0 },
+  { "STRING",        0, 0 }
+};
+
 /* GObject, GtkObject methods
  */
 static void   gtk_entry_class_init           (GtkEntryClass    *klass);
@@ -119,6 +133,29 @@ static void   gtk_entry_direction_changed    (GtkWidget        *widget,
 static void   gtk_entry_state_changed        (GtkWidget        *widget,
                                              GtkStateType      previous_state);
 
+static gboolean gtk_entry_drag_motion        (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             gint              x,
+                                             gint              y,
+                                             guint             time);
+static void     gtk_entry_drag_leave         (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             guint             time);
+static void     gtk_entry_drag_data_received (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             gint              x,
+                                             gint              y,
+                                             GtkSelectionData *selection_data,
+                                             guint             info,
+                                             guint             time);
+static void     gtk_entry_drag_data_get      (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             GtkSelectionData *selection_data,
+                                             guint             info,
+                                             guint             time);
+static void     gtk_entry_drag_data_delete   (GtkWidget        *widget,
+                                             GdkDragContext   *context);
+
 /* GtkEditable method implementations
  */
 static void     gtk_entry_insert_text          (GtkEditable *editable,
@@ -174,7 +211,8 @@ static void gtk_entry_preedit_changed_cb  (GtkIMContext      *context,
 /* Internal routines
  */
 static void         gtk_entry_draw_text                (GtkEntry       *entry);
-static void         gtk_entry_draw_cursor              (GtkEntry       *entry);
+static void         gtk_entry_draw_cursor              (GtkEntry       *entry,
+                                                       CursorType      type);
 static PangoLayout *gtk_entry_get_layout               (GtkEntry       *entry,
                                                        gboolean        include_preedit);
 static void         gtk_entry_queue_draw               (GtkEntry       *entry);
@@ -183,6 +221,7 @@ static void         gtk_entry_recompute                (GtkEntry       *entry);
 static gint         gtk_entry_find_position            (GtkEntry       *entry,
                                                        gint            x);
 static void         gtk_entry_get_cursor_locations     (GtkEntry       *entry,
+                                                       CursorType      type,
                                                        gint           *strong_x,
                                                        gint           *weak_x);
 static void         gtk_entry_adjust_scroll            (GtkEntry       *entry);
@@ -298,6 +337,12 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->direction_changed = gtk_entry_direction_changed;
   widget_class->state_changed = gtk_entry_state_changed;
 
+  widget_class->drag_motion = gtk_entry_drag_motion;
+  widget_class->drag_leave = gtk_entry_drag_leave;
+  widget_class->drag_data_received = gtk_entry_drag_data_received;
+  widget_class->drag_data_get = gtk_entry_drag_data_get;
+  widget_class->drag_data_delete = gtk_entry_drag_data_delete;
+
   class->insert_text = gtk_entry_real_insert_text;
   class->delete_text = gtk_entry_real_delete_text;
   class->move_cursor = gtk_entry_move_cursor;
@@ -629,7 +674,13 @@ gtk_entry_init (GtkEntry *entry)
   entry->editable = TRUE;
   entry->visible = TRUE;
   entry->invisible_char = '*';
+  entry->dnd_position = -1;
   
+  gtk_drag_dest_set (GTK_WIDGET (entry),
+                     GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT,
+                     target_table, G_N_ELEMENTS (target_table),
+                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
   /* This object is completely private. No external entity can gain a reference
    * to it; so we create it here and destroy it in finalize().
    */
@@ -883,7 +934,14 @@ gtk_entry_expose (GtkWidget      *widget,
   else if (entry->text_area == event->window)
     {
       gtk_entry_draw_text (GTK_ENTRY (widget));
-      gtk_entry_draw_cursor (GTK_ENTRY (widget));
+
+      if ((entry->visible || entry->invisible_char != 0) &&
+         GTK_WIDGET_HAS_FOCUS (widget) &&
+         entry->selection_bound == entry->current_pos)
+       gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
+
+      if (entry->dnd_position != -1)
+       gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
     }
 
   return FALSE;
@@ -896,6 +954,7 @@ gtk_entry_button_press (GtkWidget      *widget,
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEditable *editable = GTK_EDITABLE (widget);
   gint tmp_pos;
+  gint sel_start, sel_end;
 
   entry = GTK_ENTRY (widget);
   editable = GTK_EDITABLE (widget);
@@ -916,12 +975,26 @@ gtk_entry_button_press (GtkWidget      *widget,
       switch (event->type)
        {
        case GDK_BUTTON_PRESS:
-         gtk_entry_reset_im_context (entry);
-         
-         entry->current_pos = tmp_pos;
-         entry->selection_bound = tmp_pos;
+         if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end) &&
+             tmp_pos >= sel_start && tmp_pos <= sel_end)
+           {
+             /* Click inside the selection - we'll either start a drag, or
+              * clear the selection
+              */
 
-         gtk_entry_recompute (entry);
+             entry->in_drag = TRUE;
+             entry->drag_start_x = event->x + entry->scroll_offset;
+             entry->drag_start_y = event->y + entry->scroll_offset;
+           }
+         else
+           {
+             gtk_entry_reset_im_context (entry);
+             
+             entry->current_pos = tmp_pos;
+             entry->selection_bound = tmp_pos;
+
+             gtk_entry_recompute (entry);
+           }
          
          break;
 
@@ -962,13 +1035,28 @@ gtk_entry_button_release (GtkWidget      *widget,
                          GdkEventButton *event)
 {
   GtkEntry *entry = GTK_ENTRY (widget);
-  GtkEditable *editable = GTK_EDITABLE (widget);
 
   if (event->window != entry->text_area || entry->button != event->button)
     return FALSE;
 
+  if (entry->in_drag)
+    {
+      gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
+
+      gtk_entry_reset_im_context (entry);
+             
+      entry->current_pos = tmp_pos;
+      entry->selection_bound = tmp_pos;
+             
+      gtk_entry_recompute (entry);
+
+      entry->in_drag = 0;
+    }
+  
   entry->button = 0;
   
+  gtk_entry_update_primary_selection (entry);
+             
   return FALSE;
 }
 
@@ -985,12 +1073,35 @@ gtk_entry_motion_notify (GtkWidget      *widget,
   if (event->is_hint || (entry->text_area != event->window))
     gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL);
 
-  tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+  if (entry->in_drag)
+    {
+      if (gtk_drag_check_threshold (widget,
+                                   entry->drag_start_x, entry->drag_start_y,
+                                   event->x + entry->scroll_offset, event->y))
+       {
+         GdkDragContext *context;
+         GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
+         
+         context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY | GDK_ACTION_MOVE,
+                         entry->button, (GdkEvent *)event);
 
-  if (tmp_pos != entry->current_pos)
+         
+         entry->in_drag = FALSE;
+         entry->button = 0;
+         
+         gtk_target_list_unref (target_list);
+         gtk_drag_set_icon_default (context);
+       }
+    }
+  else
     {
-      entry->current_pos = tmp_pos;
-      gtk_entry_recompute (entry);
+      tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+
+      if (tmp_pos != entry->current_pos)
+       {
+         entry->current_pos = tmp_pos;
+         gtk_entry_recompute (entry);
+       }
     }
       
   return TRUE;
@@ -1241,6 +1352,43 @@ gtk_entry_style_set      (GtkWidget      *widget,
     }
 }
 
+static char *
+strstr_len (const char *haystack,
+           int         haystack_len,
+           const char *needle)
+{
+  int i;
+
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+  
+  if (haystack_len < 0)
+    return strstr (haystack, needle);
+  else
+    {
+      const char *p = haystack;
+      int needle_len = strlen (needle);
+      const char *end = haystack + haystack_len - needle_len;
+
+      if (needle_len == 0)
+       return (char *)haystack;
+
+      while (*p && p <= end)
+       {
+         for (i = 0; i < needle_len; i++)
+           if (p[i] != needle[i])
+             goto next;
+
+         return (char *)p;
+
+       next:
+         p += needle_len;
+       }
+    }
+
+  return NULL;
+}
+
 /* Default signal handlers
  */
 static void
@@ -1251,10 +1399,26 @@ gtk_entry_real_insert_text (GtkEntry    *entry,
 {
   gint index;
   gint n_chars;
+  gchar line_separator[7];
+  gint len;
+  gchar *p;
 
   if (new_text_length < 0)
     new_text_length = strlen (new_text);
 
+  /* We don't want to allow inserting paragraph delimeters
+   */
+  pango_find_paragraph_boundary (new_text, new_text_length, &new_text_length, NULL);
+
+  /* Or line separators - this is really painful
+   */
+  len = g_unichar_to_utf8 (0x2028, line_separator); /* 0x2028 == LS */
+  line_separator[len] = '\0';
+  
+  p = strstr_len (new_text, new_text_length, line_separator);
+  if (p)
+    new_text_length = p - new_text;
+
   n_chars = g_utf8_strlen (new_text, new_text_length);
   if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
     {
@@ -1807,39 +1971,32 @@ gtk_entry_draw_text (GtkEntry *entry)
 }
 
 static void
-gtk_entry_draw_cursor (GtkEntry *entry)
+gtk_entry_draw_cursor (GtkEntry  *entry,
+                      CursorType type)
 {
   g_return_if_fail (entry != NULL);
   g_return_if_fail (GTK_IS_ENTRY (entry));
 
-  if (!entry->visible && entry->invisible_char == 0)
-    return;
-  
   if (GTK_WIDGET_DRAWABLE (entry))
     {
       GtkWidget *widget = GTK_WIDGET (entry);
 
-      if (GTK_WIDGET_HAS_FOCUS (widget) &&
-         (entry->selection_bound == entry->current_pos))
-       {
-         gint xoffset = INNER_BORDER - entry->scroll_offset;
-         gint strong_x, weak_x;
-         gint text_area_height;
-
-         gdk_window_get_size (entry->text_area, NULL, &text_area_height);
+      gint xoffset = INNER_BORDER - entry->scroll_offset;
+      gint strong_x, weak_x;
+      gint text_area_height;
 
-         gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
-
-         gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED], 
-                        xoffset + strong_x, INNER_BORDER,
-                        xoffset + strong_x, text_area_height - INNER_BORDER);
-
-         if (weak_x != strong_x)
-           gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL], 
-                          xoffset + weak_x, INNER_BORDER,
-                          xoffset + weak_x, text_area_height - INNER_BORDER);
-
-       }
+      gdk_window_get_size (entry->text_area, NULL, &text_area_height);
+      
+      gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
+      
+      gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED], 
+                    xoffset + strong_x, INNER_BORDER,
+                    xoffset + strong_x, text_area_height - INNER_BORDER);
+      
+      if (weak_x != strong_x)
+       gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL], 
+                      xoffset + weak_x, INNER_BORDER,
+                      xoffset + weak_x, text_area_height - INNER_BORDER);
     }
 }
 
@@ -1906,22 +2063,28 @@ gtk_entry_find_position (GtkEntry *entry,
 }
 
 static void
-gtk_entry_get_cursor_locations (GtkEntry *entry,
-                               gint     *strong_x,
-                               gint     *weak_x)
+gtk_entry_get_cursor_locations (GtkEntry   *entry,
+                               CursorType  type,
+                               gint       *strong_x,
+                               gint       *weak_x)
 {
   PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
   const gchar *text;
   PangoRectangle strong_pos, weak_pos;
   gint index;
   
-  text = pango_layout_get_text (layout);
-
-  index =
-    g_utf8_offset_to_pointer (text,
-                              entry->current_pos +
-                              entry->preedit_cursor) - text;
-  
+  if (type == CURSOR_STANDARD)
+    {
+      text = pango_layout_get_text (layout);
+      index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
+    }
+  else /* type == CURSOR_DND */
+    {
+      index = g_utf8_offset_to_pointer (entry->text, entry->dnd_position) - entry->text;
+      if (entry->dnd_position > entry->current_pos)
+       index += entry->preedit_length;
+    }
+      
   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
   g_object_unref (G_OBJECT (layout));
 
@@ -1990,7 +2153,7 @@ gtk_entry_adjust_scroll (GtkEntry *entry)
    * put the weak cursor on screen if possible.
    */
 
-  gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
+  gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
   
   strong_xoffset = strong_x - entry->scroll_offset;
 
@@ -2482,3 +2645,145 @@ gtk_entry_popup_menu (GtkEntry       *entry,
                  NULL, NULL,
                  event->button, event->time);
 }
+
+static void
+gtk_entry_drag_leave (GtkWidget        *widget,
+                     GdkDragContext   *context,
+                     guint             time)
+{
+  GtkEntry *entry;
+
+  entry = GTK_ENTRY (widget);
+
+  entry->dnd_position = -1;
+  gtk_widget_queue_draw (widget);
+}
+
+static gboolean
+gtk_entry_drag_motion (GtkWidget        *widget,
+                      GdkDragContext   *context,
+                      gint              x,
+                      gint              y,
+                      guint             time)
+{
+  GtkEntry *entry;
+  GtkWidget *source_widget;
+  GdkDragAction suggested_action;
+  gint new_position, old_position;
+  gint sel1, sel2;
+  
+  entry = GTK_ENTRY (widget);
+
+  x -= widget->style->xthickness;
+  y -= widget->style->ythickness;
+  
+  old_position = entry->dnd_position;
+  new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
+
+  source_widget = gtk_drag_get_source_widget (context);
+  suggested_action = context->suggested_action;
+
+  if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
+      new_position < sel1 || new_position > sel2)
+    {
+      if (source_widget == widget)
+       {
+         /* Default to MOVE, unless the user has
+          * pressed ctrl or alt to affect available actions
+          */
+         if ((context->actions & GDK_ACTION_MOVE) != 0)
+           suggested_action = GDK_ACTION_MOVE;
+       }
+          
+      entry->dnd_position = new_position;
+    }
+  else
+    {
+      if (source_widget == widget)
+       suggested_action = 0;   /* Can't drop in selection where drag started */
+      
+      entry->dnd_position = -1;
+    }
+
+  gdk_drag_status (context, suggested_action, time);
+  
+  if (entry->dnd_position != old_position)
+    gtk_widget_queue_draw (widget);
+
+  return TRUE;
+}
+
+static void
+gtk_entry_drag_data_received (GtkWidget        *widget,
+                             GdkDragContext   *context,
+                             gint              x,
+                             gint              y,
+                             GtkSelectionData *selection_data,
+                             guint             info,
+                             guint             time)
+{
+  GtkEntry *entry;
+  GtkEditable *editable;
+  gchar *str;
+
+  entry = GTK_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+
+  str = gtk_selection_data_get_text (selection_data);
+
+  if (str)
+    {
+      gint new_position;
+      gint sel1, sel2;
+
+      new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
+
+      if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
+         new_position < sel1 || new_position > sel2)
+       {
+         gtk_editable_insert_text (editable, str, -1, &new_position);
+       }
+      else
+       {
+         /* Replacing selection */
+         gtk_editable_delete_text (editable, sel1, sel2);
+         gtk_editable_insert_text (editable, str, -1, &sel1);
+       }
+      
+      g_free (str);
+    }
+}
+
+static void
+gtk_entry_drag_data_get (GtkWidget        *widget,
+                        GdkDragContext   *context,
+                        GtkSelectionData *selection_data,
+                        guint             info,
+                        guint             time)
+{
+  gint sel_start, sel_end;
+
+  GtkEditable *editable = GTK_EDITABLE (widget);
+  
+  if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
+    {
+      gchar *str = gtk_editable_get_chars (editable, sel_start, sel_end);
+
+      gtk_selection_data_set_text (selection_data, str);
+      
+      g_free (str);
+    }
+
+}
+
+static void
+gtk_entry_drag_data_delete (GtkWidget      *widget,
+                           GdkDragContext *context)
+{
+  gint sel_start, sel_end;
+
+  GtkEditable *editable = GTK_EDITABLE (widget);
+  
+  if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
+    gtk_editable_delete_text (editable, sel_start, sel_end);
+}
index 6099ac13bce2e4465f57b43e0867af49ae724548..553837603de9c1e0571755e6dfdcb0366673d8d6 100644 (file)
@@ -58,6 +58,7 @@ struct _GtkEntry
   guint      editable : 1;
   guint      visible  : 1;
   guint      overwrite_mode : 1;
+  guint      in_drag : 1;      /* Dragging within the selection */
 
   guint16 text_length; /* length in use, in chars */
   guint16 text_max_length;
@@ -87,6 +88,11 @@ struct _GtkEntry
 
   guint16 preedit_length;      /* length of preedit string, in bytes */
   guint16 preedit_cursor;      /* offset of cursor within preedit string, in chars */
+
+  gint dnd_position;           /* In chars, -1 == no DND cursor */
+
+  gint drag_start_x;
+  gint drag_start_y;
   
   gunichar invisible_char;
 };
index 8d567e4ddea67f9f375d11867cfdf79d2bebbccc..d1e21374ecfcf142dab083570f5d2fce96132b86 100644 (file)
@@ -76,7 +76,6 @@
  */
 
 #define FOCUS_EDGE_WIDTH 1
-#define DRAG_THRESHOLD 8
 
 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window)
 #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window)
@@ -3204,16 +3203,14 @@ gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event)
       text_view->drag_start_x >= 0)
     {
       gint x, y;
-      gint dx, dy;
 
       gdk_window_get_pointer (text_view->text_window->bin_window,
                               &x, &y, NULL);
 
-      dx = text_view->drag_start_x - x;
-      dy = text_view->drag_start_y - y;
-
-      if (ABS (dx) > DRAG_THRESHOLD ||
-          ABS (dy) > DRAG_THRESHOLD)
+      if (gtk_drag_check_threshold (widget,
+                                   text_view->drag_start_x, 
+                                   text_view->drag_start_y,
+                                   x, y))
         {
           GtkTextIter iter;
           gint buffer_x, buffer_y;